/**
 * Copyright 2006 gworks.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 */
package au.com.gworks.jump.system;

import java.io.File;
import java.net.URLConnection;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContextEvent;

import org.javaongems.runtime.lang.StringUtils;


/**
 * What: Class utility used to provision application configuration information.
 * 
 * Why: The UI and other application oriented components need to be customised
 * for the specific collaboration use.
 * 
 * When: The initialisation methods are invoked by the BootStrap utility which
 * sets up the application data. This data is then access/queried typically by
 * the application layer for rendering.
 * 
 * How: The configuration data is loaded from the env.properties file. All
 * fields of the "application.*" form are loaded by the BootStrap.
 * 
 * @see au.com.gworks.jump.system.BootStrap#init()
 * @see JUMP_HOME/conf/env.properties [application.* properties]
 */
public final class ApplicationManager {
	final static public String APPL_NAME_PARAM = "application.name";
	final static public String APPL_BANNER_PATH_PARAM = "application.bannerPath";
	final static public String APPL_HEAD_PATH_PARAM = "application.headPath";
	final static public String APPL_FOOTER_PATH_PARAM = "application.footerPath";
	final static public String APPL_SYSTEM_NAMESPACE_PARAM = "application.systemNamespace";
	final static public String APPL_DEFAULT_ENTRY_NAMESPACE_PARAM = "application.defaultEntryNamespace";
	final static public String APPL_LOGIN_TIMEOUT_PARAM = "application.loginTimeout";
	final static public String APPL_TREAT_AS_RAW_DEFAULT_EXT = "application.treatAsRawDefaultExtensions";
	final static public String APPL_TREAT_AS_TEXT_DEFAULT_EXT = "application.treatAsTextDefaultExtensions";
	final static public String APPL_GUEST_USER_PARAM = "application.guestUser";
	final static public String APPL_GUEST_PASSWORD_PARAM = "application.guestPassword";
	final static public String APPL_DEFAULT_MIME_TYPE_PROPERTY_PARAM = "application.mimeTypeProperty";
	final static public String APPL_DEFAULT_BINARY_MIME_TYPE_VALUE_PARAM = "application.binaryMimeTypeValue";
	final static public String ADMINISTRATORS_PARAM = "administrators";
	final static public String IDENTITY_QUERIER_PARAM = "identityQuerier";

	final static public String DEFAULT_IDENTITYQUERIER_PARAM = "au.com.gworks.jump.system.DefaultIdentityQuerier";
	final static public String DEFAULT_BINARY_MIME_TYPE_VAL = "application/octet-stream";
	final static public String DEFAULT_MIME_TYPE_PROP = "svn:mime-type";
	final static public String DEFAULT_APP_NAME = "Jump";
	final static public String DEFAULT_BANNER = "<img alt=\"logo\" src=\"{0}/images/dharma-wheel-x80.gif\" height=\"80\" width=\"80\" border=\"0\">";
	final static public String DEFAULT_HEAD = "";
	final static public String DEFAULT_FOOTER = "";
	final static public String DEFAULT_SYSTEM_NAMESPACE = "system-repository";
	final static public String DEFAULT_GUEST_USER = "guest";
	final static public String DEFAULT_GUEST_PASSWORD = "guest";

	/**
	 * <code>applInfo</code> used to store the application.* fields sourced
	 * from the env.properties file. 
			0 - application name
			1 - default banner
			2 - default head
			3 - default footer
			4 - system namespace
			5 - guest user
			6 - guest password
			7 - default entry namespace
			8 - default mime-type property name
			9 - default binary mime-type value
	 */
	final static String[] applInfo = new String[10];

	/**
	 * <code>administrators</code> is a list of administrators as strings that
	 * are registered in the env.properties file.
	 */
	final static public List administrators = new ArrayList();

	/**
	 * <code>treatAsRawDefaultExtensions</code> is a list of extensions that
	 * are registered in the env.properties file.
	 */
	final static public List treatAsRawDefaultExtensions = new ArrayList();

	/**
	 * <code>treatAsTextDefaultExtensions</code> is a list of extensions that
	 * are registered in the env.properties file.
	 */
	final static public List treatAsTextDefaultExtensions = new ArrayList();

	/**
	 * <code>theLoginTimeOut</code> the registered session time-out interval
	 * used by the web-tier. Default: 4 hours
	 */
	static public int theLoginTimeOut = 60 * 60 * 4; // ie. 4 hours

	/**
	 * <code>mimeTypeQuerier</code> is the system's utility to query mime
	 * types. Client installations should assign a web-tier based implementation
	 * to ensure the appropriate mappings are resolved. Default:
	 * au.com.gworks.jump.system.ApplicationManager.UrlConnectionContentTypeQuerier
	 * 
	 * @see UrlConnectionContentTypeQuerier
	 * @see au.com.gworks.jump.app.util.Bootstrap#contextInitialized(ServletContextEvent)
	 */
	static public MimeTypeQuerier mimeTypeQuerier = new UrlConnectionContentTypeQuerier();

	static String JUMP_HOME;

	static IdentityQuerier theIdentityQuerier;

	static String webApplicationContext;

	private ApplicationManager() {
		// nothing to do.
	}

	/**
	 * @return the name of the Wiki application. This value is sourced from the
	 *         env.properties "application.name" property. The default value is
	 *         DEFAULT_APP_NAME. This name is typically used for all titles on
	 *         the Wiki pages.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.name)
	 */
	static public String getApplicationName() {
		if (applInfo[0] != null)
			return applInfo[0];
		return ApplicationManager.DEFAULT_APP_NAME;
	}

	/**
	 * @return the banner for the Wiki application as a HTML string. This value
	 *         is sourced from the env.properties "application.bannerPath"
	 *         property. The path content is then loaded from the active
	 *         AccountRepository and stored. The default value is
	 *         DEFAULT_BANNER. This value is typically used for all banners on
	 *         Wiki pages.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.bannerPath)
	 * @see au.com.gworks.jump.io.AccountRepository#openResource(String, Integer)
	 */
	static public String getBanner() {
		if (applInfo[1] != null)
			return applInfo[1];
		// too lazy to use formatters for this
		String banner = StringUtils.replace(DEFAULT_BANNER, "{0}", getWebApplicationContext());
		return banner;
	}

	/**
	 * @return the header for the Wiki application as a HTML string. This value
	 *         is sourced from the env.properties "application.headPath"
	 *         property. The path content is then loaded from the active
	 *         AccountRepository and stored. The default value is DEFAULT_HEAD.
	 *         This value is typically inserted within the
	 *         &lt;head&gt;...&lt;/head&gt; sections on Wiki pages. This can be
	 *         used to incorporate styles (ie. CSS) into the pages.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.headPath)
	 * @see au.com.gworks.jump.io.AccountRepository#openResource(String, Integer)
	 */
	static public String getHead() {
		if (applInfo[2] != null)
			return applInfo[2];
		return ApplicationManager.DEFAULT_HEAD;
	}

	/**
	 * @return the footer for the Wiki application as a HTML string. This value
	 *         is sourced from the env.properties "application.footerPath"
	 *         property. The path content is then loaded from the active
	 *         AccountRepository and stored. The default value is
	 *         DEFAULT_FOOTER. This value is typically used for all footers on
	 *         Wiki pages.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.footerPath)
	 * @see au.com.gworks.jump.io.AccountRepository#openResource(String, Integer)
	 */
	static public String getFooter() {
		if (applInfo[3] != null)
			return applInfo[3];
		return ApplicationManager.DEFAULT_FOOTER;
	}

	/**
	 * @return the name of the property that can be queried on ResourceAttribute
	 *         properties to return the mime-type of the resource. This value is
	 *         sourced from env.properties "application.mimeTypeProperty"
	 *         property. The default value is DEFAULT_MIME_TYPE_PROP.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.mimeTypeProperty)
	 */
	static public String getResourceMimeTypeProperty() {
		if (applInfo[8] != null)
			return applInfo[8];
		return ApplicationManager.DEFAULT_MIME_TYPE_PROP;
	}

	/**
	 * @return the name of the mime-type value that when queried on
	 *         ResourceAttribute properties is considered to be a binary
	 *         resource. This value is sourced from env.properties
	 *         "application.binaryMimeTypeValue" property. The default value is
	 *         DEFAULT_BINARY_MIME_TYPE_VAL.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.binaryMimeTypeValue)
	 */
	static public String getResourceBinaryMimeTypeValue() {
		if (applInfo[9] != null)
			return applInfo[9];
		return ApplicationManager.DEFAULT_BINARY_MIME_TYPE_VAL;
	}

	/**
	 * @return the system namespace to use when no namespace is provided.
	 *         The env.properties "application.systemNamespace" property is 
	 *         typically used but if not set then the DEFAULT_SYSTEM_NAMESPACE
	 *         will be used instead. 
	 * 
	 * JUMP_HOME/conf/env.properties (application.systemNamespace)
	 */
	static public String getSystemNamespace() {
		if (applInfo[4] != null)
			return applInfo[4];
		return ApplicationManager.DEFAULT_SYSTEM_NAMESPACE;
	}

	/**
	 * @return the guest username to display on the login screen to enable
	 *         unregistered users to function anonymously with the system. This
	 *         values is sourced from the env.properties "application.guestUser"
	 *         property. The default DEFAULT_GUEST_USER.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.guestUser)
	 */
	static public String getGuestUser() {
		if (applInfo[5] != null)
			return applInfo[5];
		return ApplicationManager.DEFAULT_GUEST_USER;
	}

	/**
	 * @return the guest password to display on the login screen to enable
	 *         unregistered users to function anonymously with the system. This
	 *         values is sourced from the env.properties
	 *         "application.guestPassword" property. The default
	 *         DEFAULT_GUEST_PASSWORD.
	 * 
	 * @see JUMP_HOME/conf/env.properties (application.guestPassword)
	 */
	static public String getGuestPassword() {
		if (applInfo[6] != null)
			return applInfo[6];
		return ApplicationManager.DEFAULT_GUEST_PASSWORD;
	}

	/**
	 * @return the namespace that will be forwarded to if no namespace was sited.
	 * 
	 * @see JUMP_HOME/conf/env.properties
	 *      (application.defaultEntryNamespace)
	 * @see http://JumpServerName:portNo/jump/visit/... (visit mode)
	 */
	static public String getDefaultEntryNamespace() {
		if (StringUtils.isEmpty(applInfo[7]))
			return getSystemNamespace();
		return applInfo[7];
	}

	/**
	 * @return true if the name provided is a registered cAID system
	 *         administrator in the env.properties "administrators" property.
	 *         This property value accepts comma delimited names which are
	 *         matched against the toChk argument.
	 * 
	 * @see JUMP_HOME/conf/env.properties (administrators)
	 */
	static public boolean isAdministrator(String toChk) {
		return administrators.indexOf(toChk) > -1;
	}

	/**
	 * @return true if the name provided is a registered cAID system
	 *         administrator in the env.properties "administrators" property.
	 *         This property value accepts comma delimited names which are
	 *         matched against the toChk argument.
	 * 
	 * @see JUMP_HOME/conf/env.properties (administrators)
	 */
	static public boolean isSystemAdministrator(Principal toChk) {
		return isAdministrator(toChk.getName());
	}

	/**
	 * @return the path representing JUMP_HOME. This is the install location of
	 *         the specific distribution of cAID. This value is used to load the
	 *         configuration and plugins of the distribution. It is set via two
	 *         methods: 1. jump.properties file in the home directory of account
	 *         executing the J2EE web-server &th;user.home&gt;/jump.properties
	 *         (JUMP_HOME) eg. JUMP_HOME=d:/JUMP/3.14.45 2. JVM argument provided
	 *         to the J2EE web-server -Djump.home=&th;cAIDv4Path&gt; eg.
	 *         -Djump.home=Z:\JUMP\4.0
	 */
	static public String getJumpHome() {
		return JUMP_HOME;
	}

	/**
	 * @return the path representing the configuration sub-folder of the AID
	 *         distribution. This value is the same as getAidHome() + "/conf/".
	 */
	static public String getJumpHomeConfSubFolder() {
		String ret = ApplicationManager.getJumpHome() + File.separator + "conf"
				+ File.separator;
		return ret;
	}

	/**
	 * @return the identity querier used in the system. This enables user names
	 *         to be queried to determine user details (eg. email address).
	 * 
	 * @see IdentityQuerier
	 */
	static public IdentityQuerier getIdentityQuerier() {
		return theIdentityQuerier;
	}

	/**
	 * @return the web application context that the application is installed
	 *         under in the J2EE web container.
	 */
	static public String getWebApplicationContext() {
		if (webApplicationContext == null)
			return "";
		return webApplicationContext;
	}

	/**
	 * What: setter method to assign the mime-type querier to be used for the
	 * system
	 * 
	 * @see #mimeTypeQuerier
	 */
	static public void setMimeType(MimeTypeQuerier querier) {
		mimeTypeQuerier = querier;
	}

	static public void initHome(String hm) {
		JUMP_HOME = hm;
	}

	static public void initIdentityQuerier(IdentityQuerier iq) {
		theIdentityQuerier = iq;
	}

	static public void init(String home, List admins, String[] info) {
		initHome(home);
		administrators.addAll(admins);
		for (int i = 0; i < info.length; i++) 
			applInfo[i] = info[i];
	}

	public static void reset() {
		administrators.clear();
		for (int i = 0; i < applInfo.length; i++) 
			applInfo[i]=null;
		JUMP_HOME = null;
		treatAsRawDefaultExtensions.clear();
		treatAsTextDefaultExtensions.clear();
	}

	/**
	 * <p>
	 * Sets the web application context that the application is configured under
	 * in the web container.
	 * </p>
	 * 
	 * <p>
	 * This should only be called upon web application initialisation.
	 * </p>
	 * 
	 * @param ctx
	 */
	static public void setWebApplicationContext(String ctx) {
		webApplicationContext = ctx;
	}

	static public class UrlConnectionContentTypeQuerier implements
			MimeTypeQuerier {
		public String getMimeType(String fileName) {
			return URLConnection.getFileNameMap().getContentTypeFor(fileName);
		}
	}

	public interface MimeTypeQuerier {
		public String getMimeType(String fileName);
	}
}
